package com.compunit.composite.core;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;

import javax.swing.JOptionPane;

import org.compunit.interfaces.ICustomizableComponent;
import org.compunit.interfaces.IResourceRetriever;

import com.compunit.composite.core.CompUnit;
import com.compunit.composite.core.cx.CxImporter;
import com.compunit.composite.core.interfaces.IAssembler;
import com.compunit.composite.core.interfaces.IConfigurationImporter;
import com.compunit.composite.core.interfaces.ILauncher;
import com.compunit.composite.core.interfaces.cx.ICxImporter;

/**
 * <code>Launcher</code> defines the implementation of
 * the utility unit that is responsible for launching
 * a given component.
 *
 * @author Yi Wang (Neakor)
 * @version Creation date: 11-13-2009 18:59 EST
 * @version Modified date: 12-05-2009 22:08 EST
 */
public class Launcher implements ILauncher {
	/**
	 * The <code>ICxImporter</code> instance.
	 */
	private final ICxImporter cxImporter;
	/**
	 * The <code>IAssembler</code> instance.
	 */
	private final IAssembler assembler;
	/**
	 * The <code>IConfigurationImporter</code>.
	 */
	private final IConfigurationImporter configImporter;
	/**
	 * The <code>Iterable</code> of current running
	 * <code>CompUnit</code> instances.
	 */
	private Iterable<CompUnit> components;
	
	/**
	 * Constructor of <code>Launcher</code>.
	 */
	public Launcher() {
		this.cxImporter = new CxImporter();
		this.assembler = new Assembler();
		this.configImporter = new ConfigurationImporter();
	}

	@Override
	public void launch(final URL directory, final String name, final boolean cache) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
		this.launch(directory, name, cache, null);
	}

	@Override
	public void launch(final URL directory, final String name, final boolean cache, final URL configfile) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
		try {
			this.shutdown();
		} catch (Exception e) {
			e.printStackTrace();
		}
		String raw = directory.getPath();
		if(!raw.endsWith("/")) raw.concat("/");
		final String path = raw.substring(raw.indexOf("/"), raw.length()).concat(name);
		final File cxfile = new File(path.concat(".cx"));
		if(!cxfile.exists()) throw new IOException("Missing CX file: ".concat(cxfile.toString()));
		final File jarfile = new File(path.concat(".jar"));
		if(!jarfile.exists()) throw new IOException("Missing class file: ".concat(jarfile.toString()));
		this.cxImporter.process(cxfile.toURI().toURL());
		this.assembler.assemble(this.cxImporter, jarfile.toURI().toURL());
		this.components = this.assembler.getComponents();
		if(configfile == null) {
			JOptionPane.showMessageDialog(null, "Launching with default configuration.");
		} else this.configImporter.process(configfile);
		Properties properties = (configfile==null) ? new Properties() : null;
		for(final CompUnit unit : this.components) {
			try {
				IResourceRetriever retriever = null;
				if(unit.resourcename != null) retriever = new ResourceRetriever(directory, unit.resourcename, cache);
				if(unit.instance instanceof ICustomizableComponent) {
					if(configfile != null) properties = this.configImporter.get(unit.instance.getClass().getName());
					((ICustomizableComponent)unit.instance).customize(properties);
				}
				unit.instance.activate(retriever);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void shutdown() throws Exception {
		if(this.components == null) return;
		for(final CompUnit unit : this.components) unit.instance.deactivate();
	}
}
